#ifndef VECTOR_H
#define	VECTOR_H

/*
 * Vector do not keeps order of elements after delete or sort operations.
 *
 * API:
 * define_struct(Type for storing in vector,Name of vector type)
 * This macro defines structure, that represents vector, giving basis for all
 * other operations
 *
 * define_vector(Type,Name)
 * Defines a set of operations with vector, based on given name.
 *
 * Vector* Name_init(Vector*,Reserved Capacity,Overflow multiplier) - initializes
 * contents of structure, that represents vector. Return value reflects the
 * result of memory allocation: 0 on fail and same vector structure pointer on
 * success. Reserved capacity determines the size of initial memory allocation,
 * while Overflow multiplier determines how much the capacity of this vector
 * must be increased when no more place left to new elements;
 *
 * void Name_reset(Vector*) - resets vector parameters, to it can be treated as
 * a newly created, but with the same capacity as initial vector. Attribute "size"
 * and "sorted" will be set to zero after this operation.
 *
 * void Name_release(Vector*) - performs release of memory, allocated for vector
 * After this operation, vector becomes unusable, unless new initialization.
 *
 *  Name_resize(Vector*,New Capacity) - resizing vector to the given capacity.
 * This function can change capacity in any direction, hovewer, it's decreasing
 * inevitably leads to decreasing vector size, and, so, losing some data.
 * Return value represents result of memory allocation: 0 on fail and same
 * vector structure pointer on success.
 *
 * Element* Name_add(Vector*) - returns pointer to new element in vector,
 * resizing array if needed
 *
 * void Name_sort(Vector*,Compare Function) - sorts specified vector.
 * Also performs check on array state ("sorted" field) to prevent unneeded sorting
 *
 * Element* Name_bsearch(Vector*,Key Element,Compare Function) - performs
 * binary search for key element in specified vector. Sorts array before search.
 * This function cannot perform search for multiple elements.
 *
 * Element* Name_linsearch(Vector*,Key Element,Compare Function) - performs
 * linear search for key element in specified vector. Iteration: left -> right.
 * Only first element, that fulfills compare function is returned. This function
 * cannot perform search for multiple elements. 
 *
 */

#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#define define_vector(type,name) \
define_init(type,name) \
define_reset(type,name) \
define_release(type,name) \
define_resize(type,name) \
define_add(type,name) \
define_del(type,name) \
define_sort(type,name) \
define_bsearch(type,name) \
define_linsearch(type,name)

#define VAL(vector,idx) ((vector)->data[(idx)])
#define FIRST(vector) ((vector)->data[0])
#define LAST(vector) ((vector)->data[(vector)->size-1])

#define define_struct(type,name) \
struct name \
{ \
    type *data; \
    size_t size; \
    size_t capacity; \
    float multiplier; \
    unsigned char sorted; \
}; \
typedef struct name name;

#define define_init(type,name) \
name *name##_init(name *vec,size_t reserve,float multiplier) \
{ \
    vec->size = 0; \
    vec->sorted = 0; \
    vec->capacity = reserve; \
    vec->multiplier = multiplier; \
    vec->data = (type*) malloc(sizeof (type) *(vec->capacity)); \
    if (NULL == vec->data) { \
        return 0; \
    } else { \
        return vec; \
    } \
}

#define define_reset(type,name) \
void name##_reset(name *vec) \
{ \
    vec->size = 0; \
    vec->sorted = 0; \
}

#define define_release(type,name) \
void name##_release(name *vec) \
{ \
    free(vec->data); \
}

#define define_resize(type,name) \
name *name##_resize(name *vec, size_t new_capacity) { \
    Log(3,"resizing to %d",new_capacity); \
    void *new_data = realloc(vec->data, new_capacity * sizeof (type)); \
    if (NULL == new_data) { \
        Log_msg(3,"Realloc error"); \
        return 0; \
    } else { \
        if(vec->capacity > new_capacity) { \
            vec->size = new_capacity; \
        } \
        vec->data = new_data; \
        vec->capacity = new_capacity; \
        return vec; \
    } \
}

/*Log(1,"capacity: %d  size: %d",vec->capacity,vec->size); */
#define define_add(type,name) \
type *name##_add(name *vec) { \
    Log(1,"Add element: size: %i capacity: %i",vec->size,vec->capacity); \
    if (vec->size >= vec->capacity) { \
        if (!name##_resize(vec, vec->capacity * vec->multiplier)) { \
            Log_msg(1,"Adding new element failed"); \
            return 0; \
        } \
    } \
    vec->sorted = 0; \
    return &(vec->data[vec->size++]); \
}

#define define_del(type,name) \
name *name##_del(name *vec,type *element) \
{ \
    if((element - vec->data)>=0 && (element - &(vec->data[vec->size-1])) <= 0) { \
        memcpy(element,&(vec->data[--(vec->size)]),sizeof(type)); \
        vec->sorted = 0; \
    } else { \
        Log_msg(3,"fail delete"); \
    } \
    return vec; \
}

//typedef int (*cmp_func)(const void*, const void*);

extern void quicksort(void *base, unsigned num, unsigned width, int (*comp)(const void *, const void *));

#define define_sort(type,name) \
void name##_sort(name *vec,cmp_func cmp) { \
    if(!vec->sorted) { \
        quicksort(vec->data, vec->size, sizeof(type), cmp); \
        vec->sorted = 1; \
    } \
}

#define define_bsearch(type,name) \
type* name##_bsearch(name *vec, type *key, cmp_func cmp) { \
    name##_sort(vec,cmp); \
    return bsearch(key, vec->data, vec->size, sizeof (type), cmp); \
}

#define define_linsearch(type,name) \
type* name##_linsearch(name *vec,type *key, cmp_func cmp) { \
    size_t i; \
    for(i=0;i<vec->size;i++) { \
        if (cmp(&VAL(vec,i),key) == 1) { \
            return &VAL(vec,i); \
        } \
    } \
    return 0; \
}

#endif	/* VECTOR_H */

